package com.ruoyi.teaching.service.impl;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.teaching.domain.YaClass;
import com.ruoyi.teaching.domain.YaCourseDesignDetail;
import com.ruoyi.teaching.domain.YaHoliday;
import com.ruoyi.teaching.dto.MyPlanDTO;
import com.ruoyi.teaching.dto.PreviewTeachingPlanDTO;
import com.ruoyi.teaching.index.CourseSchedule;
import com.ruoyi.teaching.mapper.*;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.ruoyi.teaching.domain.YaTeachingPlan;
import com.ruoyi.teaching.service.IYaTeachingPlanService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 教学计划(课)Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-03-17
 */
@Service
public class YaTeachingPlanServiceImpl extends ServiceImpl<YaTeachingPlanMapper, YaTeachingPlan> implements IYaTeachingPlanService
{
    public static final String RESTDAY = ":restday";
    public static final String SELFSTUDYDAY = ":selfstudyday";
    public static final String WORKDAY = ":workday";
    public static final String REST_DAY = "休息";
    public static final String SELF_STUDY_DAY = "自习";
    @Autowired
    private YaTeachingPlanMapper yaTeachingPlanMapper;
    @Autowired
    private YaClassMapper yaClassMapper;
    @Autowired
    private YaCourseDesignDetailMapper yaCourseDesignDetailMapper;
    @Autowired
    private YaHolidayMapper yaHolidayMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;


    /**
     * 查询教学计划(课)
     * 
     * @param id 教学计划(课)主键
     * @return 教学计划(课)
     */
    @Override
    public YaTeachingPlan selectYaTeachingPlanById(Long id)
    {
        return yaTeachingPlanMapper.selectYaTeachingPlanById(id);
    }

    /**
     * 查询教学计划(课)列表
     * 
     * @param yaTeachingPlan 教学计划(课)
     * @return 教学计划(课)
     */
    @Override
    public List<YaTeachingPlan> selectYaTeachingPlanList(YaTeachingPlan yaTeachingPlan)
    {
        return yaTeachingPlanMapper.selectYaTeachingPlanList(yaTeachingPlan);
    }

    /**
     * 新增教学计划(课)
     * 
     * @param yaTeachingPlan 教学计划(课)
     * @return 结果
     */
    @Override
    public int insertYaTeachingPlan(YaTeachingPlan yaTeachingPlan)
    {
        return yaTeachingPlanMapper.insertYaTeachingPlan(yaTeachingPlan);
    }

    /**
     * 修改教学计划(课)
     * 
     * @param yaTeachingPlan 教学计划(课)
     * @return 结果
     */
    @Override
    public int updateYaTeachingPlan(YaTeachingPlan yaTeachingPlan)
    {
        return yaTeachingPlanMapper.updateYaTeachingPlan(yaTeachingPlan);
    }

    /**
     * 批量删除教学计划(课)
     * 
     * @param ids 需要删除的教学计划(课)主键
     * @return 结果
     */
    @Override
    public int deleteYaTeachingPlanByIds(Long[] ids)
    {
        return yaTeachingPlanMapper.deleteYaTeachingPlanByIds(ids);
    }

    /**
     * 删除教学计划(课)信息
     * 
     * @param id 教学计划(课)主键
     * @return 结果
     */
    @Override
    public int deleteYaTeachingPlanById(Long id)
    {
        return yaTeachingPlanMapper.deleteYaTeachingPlanById(id);
    }

    @Override
    @Transactional(readOnly = true)
    public List<YaTeachingPlan> previewTeachingPlan(PreviewTeachingPlanDTO previewTeachingPlanDTO) {

        String className = previewTeachingPlanDTO.getClassName();

        //获取到班级正常休息日和自习日
        QueryWrapper<YaClass> yaClassQueryWrapper = new QueryWrapper<>();
        yaClassQueryWrapper.eq("class_name", className);
        YaClass yaClass = yaClassMapper.selectOne(yaClassQueryWrapper);
        Long restDay = yaClass.getRestDay();
        Long selfStudyDay = yaClass.getSelfStudyDay();

        //查询指定阶段的所有课程设计
        Integer   stage = previewTeachingPlanDTO.getStage();
        Long courseId = previewTeachingPlanDTO.getCourseId();
        LambdaQueryWrapper<YaCourseDesignDetail> yaCourseDesignQueryWrapper = new LambdaQueryWrapper<>();
        yaCourseDesignQueryWrapper.eq(YaCourseDesignDetail::getStage, stage);
        yaCourseDesignQueryWrapper.eq(YaCourseDesignDetail::getCourseId, courseId);
        List<YaCourseDesignDetail> courseDesignList = yaCourseDesignDetailMapper.selectList(yaCourseDesignQueryWrapper);

        //查询起始日期以后的所有节假日
        LambdaQueryWrapper<YaHoliday> yaHolidayLambdaQueryWrapper = new LambdaQueryWrapper<>();
        yaHolidayLambdaQueryWrapper.ge(YaHoliday::getDate, previewTeachingPlanDTO.getBeginDate());
        Map<String, String> holidayMap = yaHolidayMapper.selectList(yaHolidayLambdaQueryWrapper).stream().collect(Collectors.toMap(YaHoliday::getDate, YaHoliday::getDescription));

        //获取到班级特殊 休息日 和 自习日，上课日
        Map<Object, Object> specialRestDayMap = stringRedisTemplate.opsForHash().entries(className + RESTDAY);
        Map<Object, Object> specialSelfStudyDayMap = stringRedisTemplate.opsForHash().entries(className + SELFSTUDYDAY);
        Map<Object, Object> specialWorkDayMap = stringRedisTemplate.opsForHash().entries(className + WORKDAY);


        int size = courseDesignList.size();
        int day = 1;
        //从起始日期开始遍历（排课）
        LocalDate currentDay = LocalDate.parse(previewTeachingPlanDTO.getBeginDate());
        List<YaTeachingPlan> result = new ArrayList<>(size<<1);
        do{
            YaTeachingPlan yaTeachingPlan = new YaTeachingPlan();
            String currentDayString = currentDay.toString();
            //公共字段
            yaTeachingPlan.setDate(currentDayString);
            yaTeachingPlan.setWeekday((long)currentDay.getDayOfWeek().getValue());
            yaTeachingPlan.setClassesId(yaClass.getId());
            yaTeachingPlan.setStage((long)stage);
            yaTeachingPlan.setClassName(className);
            yaTeachingPlan.setCourseId(courseId);

            //判断是否国家法定节假日
            if (holidayMap.containsKey(currentDayString)) {
                yaTeachingPlan.setCourseContent(holidayMap.get(currentDayString));
            }
            //判断是否班级特殊自习/休息
            else if(specialRestDayMap.containsKey(currentDayString)){
                yaTeachingPlan.setCourseContent(REST_DAY);
            }
            else if(specialSelfStudyDayMap.containsKey(currentDayString)){
                yaTeachingPlan.setCourseContent(SELF_STUDY_DAY);
            }
            //判断是否班级正常休息 并且 不在班级特殊上课日中
            else if(yaTeachingPlan.getWeekday().equals(restDay)&&!specialWorkDayMap.containsKey(currentDayString)){
                yaTeachingPlan.setCourseContent(REST_DAY);
            }
            //判断是否班级正常自习 并且 不在班级特殊上课日中
            else if(yaTeachingPlan.getWeekday().equals(selfStudyDay)&&!specialWorkDayMap.containsKey(currentDayString)){
                yaTeachingPlan.setCourseContent(SELF_STUDY_DAY);
            }
            //正常上课
            else {
                YaCourseDesignDetail yaCourseDesign = courseDesignList.get(day - 1);
                yaTeachingPlan.setCourseContent(yaCourseDesign.getCourseContent());
                yaTeachingPlan.setCourseDesignDetailId(yaCourseDesign.getId());
                yaTeachingPlan.setDay((long)day++);
            }
            //获取下一天
            currentDay = currentDay.plusDays(1);
            //加入课表
            result.add(yaTeachingPlan);
        }while (day<=size);

        //返回预览课表
        return result;
    }

    @Override
    public void addWorkday(PreviewTeachingPlanDTO previewTeachingPlanDTO) {
        String className = previewTeachingPlanDTO.getClassName();
        String date = previewTeachingPlanDTO.getDate();
        //新增到工作日集合
        stringRedisTemplate.opsForHash().put(className + WORKDAY, date, WORKDAY);
        //从两个非工作日中删除
        stringRedisTemplate.opsForHash().delete(className+RESTDAY,date);
        stringRedisTemplate.opsForHash().delete(className+SELFSTUDYDAY,date);
    }

    @Override
    public void addHoliday(PreviewTeachingPlanDTO previewTeachingPlanDTO) {
        String className = previewTeachingPlanDTO.getClassName();
        //根据类型新增到对应的非上课日集合
        String type = previewTeachingPlanDTO.getType();
        String date = previewTeachingPlanDTO.getDate();
        if (REST_DAY.equals(type)) {
            stringRedisTemplate.opsForHash().put(className + RESTDAY, date, type);
        } else {
            stringRedisTemplate.opsForHash().put(className + SELFSTUDYDAY, date, type);
        }

        //删除上课日集合中的数据
        stringRedisTemplate.opsForHash().delete(className+WORKDAY,date);
    }

    @Override
    public void clearConfig(PreviewTeachingPlanDTO previewTeachingPlanDTO) {
        // 删除班级特有配置
        String className = previewTeachingPlanDTO.getClassName();
        // 修正：opsForHash().delete需要传入字段参数，这里使用delete(key)清空整个哈希
        stringRedisTemplate.delete(className + WORKDAY);
        stringRedisTemplate.delete(className + RESTDAY);
        stringRedisTemplate.delete(className + SELFSTUDYDAY);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchInsertYaTeachingPlan(List<YaTeachingPlan> yaTeachingPlanList) {
        return this.saveBatch(yaTeachingPlanList, 100)?1:0;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int deleteTeachingPlan(YaTeachingPlan yaTeachingPlan) {
        if (yaTeachingPlan.getClassName() == null) {
            throw new ServiceException("班级不能为空");
        }
        if (yaTeachingPlan.getStage() == null) {
            throw new ServiceException("阶段不能为空");
        }
        return yaTeachingPlanMapper.deleteTeachingPlan(yaTeachingPlan);
    }

    @Override
    public int batchUpdateYaTeachingPlan(List<YaTeachingPlan> yaTeachingPlanList) {
        return yaTeachingPlanMapper.updateBatch(yaTeachingPlanList);
    }

    @Override
    public void exportEs() {
        // 从 MySQL 数据库中查询 ya_teaching_plan 表的所有数据
        List<YaTeachingPlan> teachingPlanList = yaTeachingPlanMapper.selectList(null);
    
        // 将 YaTeachingPlan 对象列表转换为 CourseSchedule 对象列表
        List<CourseSchedule> courseScheduleList = teachingPlanList.stream()
                .map(this::convertToCourseSchedule)
                .collect(Collectors.toList());
    
        // 使用 ElasticsearchRestTemplate 将 CourseSchedule 对象列表批量插入到对应的索引中
        elasticsearchRestTemplate.save(courseScheduleList);
    }

    /**
     * 将 YaTeachingPlan 对象转换为 CourseSchedule 对象
     * @param teachingPlan YaTeachingPlan 对象
     * @return CourseSchedule 对象
     */
    private CourseSchedule convertToCourseSchedule(YaTeachingPlan teachingPlan) {
        CourseSchedule courseSchedule = new CourseSchedule();
        // 假设 CourseSchedule 和 YaTeachingPlan 有相同的属性名
        BeanUtils.copyProperties(teachingPlan, courseSchedule);
        return courseSchedule;
    }


    @Autowired
    private YaStudentMapper yaStudentMapper;

    @Override
    public List<YaTeachingPlan> selectMyPlanList(MyPlanDTO myPlanDTO) {
        String userName = SecurityUtils.getUsername();
        String className = yaStudentMapper.selectClassNameByStudentName(userName);
        myPlanDTO.setClassName(className);
    
        // 构建查询条件
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("className", myPlanDTO.getClassName()));
        nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("stage", myPlanDTO.getStage()));

        // 执行查询并将结果转换为 YaTeachingPlan 列表
        List<YaTeachingPlan> myPlanList = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), CourseSchedule.class)
               .getSearchHits()
               .stream()
               .map(searchHit -> {
                    CourseSchedule courseSchedule = searchHit.getContent();
                    YaTeachingPlan teachingPlan = new YaTeachingPlan();
                    BeanUtils.copyProperties(courseSchedule, teachingPlan);
                    return teachingPlan;
                }).collect(Collectors.toList());
    
        return myPlanList;
    }
}
